using System;
using System.Web;
using System.Web.UI;
using SubversionReports.Entities;
using SubversionReports.Utilities;
using Wilco.SyntaxHighlighting.Web;

namespace SubversionReports.Web.Controls
{
    public partial class FileView : UserControl
    {
        private int revisionId;
        private string path;
        private string author;
        private Repository fileLog;

        /// <summary>
        /// Gets or sets the revision id.
        /// </summary>
        /// <value>The revision id.</value>
        public int RevisionId
        {
            get
            {
                if (Request["RevisionId"] != null)
                    int.TryParse(Request["RevisionId"], out revisionId);
                return revisionId;
            }
            set { revisionId = value; }
        }

        /// <summary>
        /// Gets or sets the path.
        /// </summary>
        /// <value>The path.</value>
        public string Path
        {
            get { return Request["Path"] ?? path; }
            set { path = value; }
        }

        /// <summary>
        /// Gets or sets the author.
        /// </summary>
        /// <value>The author.</value>
        public string Author
        {
            get
            {
                if (string.IsNullOrEmpty(author))
                    author = GetRevisionAuthor(RevisionId);
                return author;
            }
            set { author = value; }
        }

        /// <summary>
        /// Gets the file log.
        /// </summary>
        /// <value>The file log.</value>
        public Repository FileLog
        {
            get
            {
                if(fileLog == null)
                    fileLog = SvnWebDav.GetFileLog(SvnWebDav.CurrentRepositoryRootUrl, SvnWebDav.CurrentRepositoryUsername, SvnWebDav.CurrentRepositoryPassword, Path);
                return fileLog;
            }
        }

        /// <summary>
        /// Gets the revision author.
        /// </summary>
        /// <param name="revisionId">The revision id.</param>
        /// <returns></returns>
        protected string GetRevisionAuthor(int revisionId)
        {
            return FileLog.Find(delegate(Revision revision) { return revision.Id.Equals(revisionId); }).Author;
        }

        /// <summary>
        /// Handles the Load event of the Page control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Visible && !string.IsNullOrEmpty(Path))
            {
                try
                {
                    //Header.Text = Path;
                    RevisionLink.Text = string.Format("All files modified in Revision {0}", RevisionId);
                    RevisionLink.NavigateUrl = string.Format("{0}?RevisionId={1}", Request.FilePath, RevisionId);

                    if (RevisionId.Equals(0)) RevisionId = SvnWebDav.GetLastRevisionNumber(SvnWebDav.CurrentRepositoryRootUrl, SvnWebDav.CurrentRepositoryUsername, SvnWebDav.CurrentRepositoryPassword);

                    SetUpBrowseLinks();

                    if(Request["CompareTo"] == null)
                    {
                        Description.Text = string.Format("Revision {0}: {1} by {2}", RevisionId, GetRevisionType(RevisionId), Author);
                        SourceViewContainer.Visible = true;
                        DiffView1.Visible = false;
                        TextFileContents.Visible = true;
                        DisplaySourceCode();
                    }
                    else
                    {
                        Description.Text = string.Format("Revision {0}: {4} by {1} compared to revision {2}: {5} by {3}", RevisionId, Author, Request["CompareTo"], GetRevisionAuthor(int.Parse(Request["CompareTo"])), GetRevisionType(RevisionId), GetRevisionType(int.Parse(Request["CompareTo"])));
                        SourceViewContainer.Visible = false;
                        DiffView1.Visible = true;
                        TextFileContents.Visible = false;
                    }
                }
                catch
                {
                    //We could be dealing with a folder rather than a file
                    Response.Redirect(Request.RawUrl.Replace("RevisionId=", "RI="), true);
                }
            }
        }

        /// <summary>
        /// Displays the source code.
        /// </summary>
        private void DisplaySourceCode()
        {
            string language = SyntaxHighlighterHandler.GetLanguageFromFilename(Path);
            string sourceCode = SvnWebDav.GetFileRevisionFromWebDav(SvnWebDav.CurrentRepositoryRootUrl, SvnWebDav.CurrentRepositoryUsername, SvnWebDav.CurrentRepositoryPassword, RevisionId, Path);
            if (language == null && sourceCode.TrimStart().StartsWith("<"))
                language = "XML";
            if(language != null)
            {
                SyntaxHighlighter1.Language = language;
                SyntaxHighlighter1.Text = sourceCode;
            }
            else
                TextFileContents.Text = HttpUtility.HtmlEncode(sourceCode);
            SyntaxHighlighter1.Visible = HighlighterCredits.Visible = (language != null);
            SourceViewContainer.Visible = (language == null);
        }

        /// <summary>
        /// Sets the up browse links.
        /// </summary>
        private void SetUpBrowseLinks()
        {
            if (RevisionId > FileLog.LowestRevision)
            {
                GoToFirstLink.NavigateUrl = string.Format("{0}?RevisionId={1}&Path={2}", Request.FilePath, FileLog.LowestRevision, Path);

                int previousRevision = GetPreviousRevision(RevisionId);

                GoToPreviousLink.Enabled = true;
                GoToPreviousLink.NavigateUrl = string.Format("{0}?RevisionId={1}&Path={2}", Request.FilePath, previousRevision, Path);
                GoToPreviousImageLink.NavigateUrl = GoToPreviousLink.NavigateUrl;
                GoToPreviousLink.Text = string.Format("go to revision {0}", previousRevision);


                int previousToPreviousRevision = GetPreviousRevision(previousRevision);
                if (previousToPreviousRevision > 0)
                {
                    CompareToPreviousLink.Enabled = true;
                    CompareToPreviousLink.NavigateUrl = string.Format("{0}?RevisionId={1}&CompareTo={2}&Path={3}", Request.FilePath, previousRevision, previousToPreviousRevision, Path);
                    CompareToPreviousImageLink.NavigateUrl = CompareToPreviousLink.NavigateUrl;
                    CompareToPreviousLink.Text = string.Format("compare {0}({1}) to {2}({3})", previousRevision, GetRevisionAuthor(previousRevision), previousToPreviousRevision, GetRevisionAuthor(previousToPreviousRevision));
                }
            }
            if (RevisionId < FileLog.HighestRevision)
            {
                GoToLastLink.NavigateUrl = string.Format("{0}?RevisionId={1}&Path={2}", Request.FilePath, FileLog.HighestRevision, Path);
                
                int nextRevision = GetNextRevision(RevisionId);

                GoToNextLink.Enabled = true;
                GoToNextLink.NavigateUrl = string.Format("{0}?RevisionId={1}&Path={2}", Request.FilePath, nextRevision, Path);
                GoToNextImageLink.NavigateUrl = GoToNextLink.NavigateUrl;
                GoToNextLink.Text = string.Format("go to revision {0}", nextRevision);

                CompareToNextLink.Enabled = true;
                CompareToNextLink.NavigateUrl = string.Format("{0}?RevisionId={1}&CompareTo={2}&Path={3}", Request.FilePath, nextRevision, RevisionId, Path);
                CompareToNextImageLink.NavigateUrl = CompareToNextLink.NavigateUrl;
                CompareToNextLink.Text = string.Format("compare {0}({1}) to {2}({3})", nextRevision, GetRevisionAuthor(nextRevision), RevisionId, Author);
            }
            GoToFirstLink.ImageUrl = GoToPreviousLink.Enabled ? "~/Images/first-active.png" : "~/Images/first-inactive.png";
            GoToLastLink.ImageUrl = GoToNextLink.Enabled ? "~/Images/last-active.png" : "~/Images/last-inactive.png";
            GoToPreviousImageLink.ImageUrl = GoToPreviousLink.Enabled ? "~/Images/previous-active.png" : "~/Images/previous-inactive.png";
            GoToNextImageLink.ImageUrl = GoToNextLink.Enabled ? "~/Images/next-active.png" : "~/Images/next-inactive.png";
            CompareToPreviousImageLink.ImageUrl = CompareToPreviousLink.Enabled ? "~/Images/previous-active.png" : "~/Images/previous-inactive.png";
            CompareToNextImageLink.ImageUrl = CompareToNextLink.Enabled ? "~/Images/next-active.png" : "~/Images/next-inactive.png";
        }

        /// <summary>
        /// Gets the next revision.
        /// </summary>
        /// <returns></returns>
        private int GetNextRevision(int current)
        {
            int next;
            try { next = FileLog.Filter("Id", current + 1, FileLog.HighestRevision, FilterType.Include).LowestRevision; }
            catch { next = 0; }
            return next;
        }

        /// <summary>
        /// Gets the previous revision.
        /// </summary>
        /// <returns></returns>
        private int GetPreviousRevision(int current)
        {
            int previous;
            try { previous = FileLog.Filter("Id", FileLog.LowestRevision, current - 1, FilterType.Include).HighestRevision; }
            catch { previous = 0; }
            return previous;
        }

        /// <summary>
        /// Handles the Click event of the ViewFileRevisionLogButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected void ViewFileRevisionLogButton_Click(object sender, EventArgs e)
        {
            HistoryView1.Visible = (!HistoryView1.Visible);
            ViewFileRevisionLogButton.ImageUrl = (HistoryView1.Visible) ? "~/Images/minus.png" : "~/Images/plus.png";
            if(HistoryView1.Visible)
            {
                HistoryView1.FileLog = FileLog;
            }
        }

        /// <summary>
        /// Gets the type of the revision.
        /// </summary>
        /// <param name="revision">The revision.</param>
        /// <returns></returns>
        private string GetRevisionType(Revision revision)
        {
            if (revision != null)
            {
                Path path1 = revision.Paths.Find(delegate(Path p) { return p.RevisionPath.Equals(Path); });
                if (path1 != null)
                    return path1.RevisionType.ToString();
            }
            return string.Empty;
        }

        /// <summary>
        /// Gets the type of the revision.
        /// </summary>
        /// <param name="revisionId">The revision id.</param>
        /// <returns></returns>
        private string GetRevisionType(int revisionId)
        {
            return GetRevisionType(FileLog.Find(delegate(Revision revision) { return revision.Id.Equals(revisionId); }));
        }
    }
}